package stringMatching;

import java.util.ArrayList;
import java.util.List;

public class KMP {
    public static void main(String[] args) {
      //  ABABABCABABC
        String text = "ABABDABACDABABCABAB";
        String pattern = "ABABCABAB";

        int matches = kmpSearch(text, pattern);
        System.out.println("匹配起始位置: " + matches);  //

        List<Integer> matches2 = KmpSearch01(text, pattern);
        matches2.forEach(System.out::println);
    }

    public static int[] getLPS(String p) {
        int[] lps = new int[p.length()];
        int len = 0;
        lps[0] = 0;
        for (int i = 1; i < p.length(); i++) {
            if (p.charAt(i) == p.charAt(len)) {
                len++;
            }
            while (p.charAt(i) != p.charAt(len) && len > 0) {
                len = lps[len - 1];
            }

            lps[i] = len;
        }
        return lps;
    }

    public static int kmpSearch(String s, String p) {
        int[] lps = getLPS(p);
        int i = 0, j = 0;
        while (i < s.length()) {
            if (s.charAt(i) == p.charAt(j)) {
                i++;
                j++;
            }
            if (j == p.length()) {
                return i - j;
            }  if (i < s.length() && s.charAt(i) != p.charAt(j)) {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }

        }
            return -1;
    }
    public static List<Integer> KmpSearch01(String text, String pattern){
        List<Integer> matches = new ArrayList<Integer>();
        int[] next = computePrefix(pattern);
        int j = 0,i = 0;
        while(i < text.length()){
            if(text.charAt(i) == pattern.charAt(j)){
                i++;
                j++;
            }
            if(j == pattern.length()){
                matches.add(i - j);
                j = next[j - 1];
            }else if(i < text.length() && text.charAt(i) != pattern.charAt(j)){
                if(j != 0){
                    j = next[j - 1];
                }else{
                    i++;
                }
            }
        }
        return matches;
    }
    public static int[] computePrefix(String pattern){
        int[] next = new int[pattern.length()];
        int len = 0;
        next[0] = 0;
        for(int i = 1; i < pattern.length(); i++){
            if(pattern.charAt(i) == pattern.charAt(len)){
                len++;
            }
            while(len >0 && pattern.charAt(i) != pattern.charAt(len)){
                len = next[len - 1];
            }
            next[i] = len;
        }
        return next;
    }
}
